package com.yyoo.doc.mypdf.builder;

import com.lowagie.text.Element;
import com.yyoo.doc.html.sax.SaxHtmlElement;
import com.yyoo.doc.html.style.StyleAttr;
import com.yyoo.doc.html.tag.HtmlTag;
import lombok.Data;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 解析 html 标签，构建 pdf Element
 * 文本标签：p, span, tr, td, th, div, h1, h2, h3, h4, h5, h6
 * 图像标签：img
 * 表格标签：table
 *
 * @author zzy
 */
@Data
public abstract class PdfElementBuilder extends PdfStyleBuilder {

    /**
     * 当前要解析的元素的父 pdf 元素对象
     */
    private Element parentPdfEl;

    /**
     * 创建 HtmlTagBuilder
     * @param htmlEl html 元素对象
     * @param cssStyleMap css 样式（style标签和link标签按优先级合并后的样式）属性
     * @return HtmlTagBuilder 对象
     */
    public static PdfElementBuilder newInstance(SaxHtmlElement htmlEl, Element parentPdfEl, Map<String,String> cssStyleMap){
        String tagName = htmlEl.getTagName().toLowerCase();
        PdfElementBuilder builder = getPdfElementBuilder(tagName);
        if(builder == null) {
            return null;
        }

        // 设置当前元素
        builder.setHtmlEl(htmlEl);
        // 设置当前 pdf 元素的父元素（如果父元素为 html 的body，则为null）
        builder.setParentPdfEl(parentPdfEl);
        // 初始化默认样式
        builder.initDefaultStyle();
        // 初始化标签属性
        builder.parseStyleAttr(cssStyleMap);

        return builder;
    }

    private static PdfElementBuilder getPdfElementBuilder(String tagName) {
        PdfElementBuilder builder = null;
        if(HtmlTag.TEXT_TAGS.contains(tagName) || HtmlTag.STYLE.equalsIgnoreCase(tagName)){
            builder = new PdfPhraseBuilder();
        }else if(HtmlTag.BLOCK_TEXT_TAGS.contains(tagName)){
            builder = new PdfParagraphBuilder();
        }else if(HtmlTag.LIST_TAGS.contains(tagName)){
            builder = new PdfListBuilder();
        }else if(HtmlTag.TABLE.equalsIgnoreCase(tagName)){
            builder = new PdfTableBuilder();
        }else if(HtmlTag.TABLE_CELL_TAGS.contains(tagName)){
            builder = new PdfTableCellBuilder();
        }else if(HtmlTag.IMG.equalsIgnoreCase(tagName)){
            builder = new PdfImageBuilder();
        }else if(HtmlTag.PAGE_HEADER.equals(tagName) || HtmlTag.PAGE_FOOTER.equals(tagName)){
            builder = new PdfHeaderFooterBuilder();
        }
        return builder;
    }

    /**
     * 创建 HtmlTagBuilder
     * @param htmlEl html 元素对象
     * @return HtmlTagBuilder 对象
     */
    public static PdfElementBuilder newInstance(SaxHtmlElement htmlEl, Element parentPdfEl){
        return newInstance(htmlEl,parentPdfEl,null);
    }

    /**
     * 解析 style 属性
     *
     * @param cssStyleMap css 样式（style标签和link标签按优先级合并后的样式）属性
     */
    private void parseStyleAttr(Map<String,String> cssStyleMap) {

        // 先添加 css 样式（style标签和link标签按优先级合并后的样式）
        addStyle(cssStyleMap);

        if(this.getHtmlEl() == null || this.getHtmlEl().getAttributeValue("style") == null){
            return;
        }
        String styleStr = getHtmlEl().getAttributeValue("style");
        Pattern pattern = Pattern.compile("([\\w-]+)\\s*:\\s*([^;]+)");
        Matcher matcher = pattern.matcher(styleStr);

        while (matcher.find()) {
            String property = matcher.group(1).trim().toLowerCase();
            String value = matcher.group(2)
                    // 清除空格
                    .trim()
                    // 清除引号
                    .replace("'", "").replace("\"", "");
            // style 属性的样式，将覆盖 css 同名样式
            addStyle(property, value);
        }


    }

    /**
     * 添加样式（相同样式将覆盖）
     * StyleAttr.SUPPORT_STYLE_KEYS 支持的样式才能添加成功
     * @param key 样式名称
     * @param value 样式值
     */
    public void addStyle(String key, String value){
        if(StyleAttr.isSupportStyleKey(key.toLowerCase())){
            getStyleMap().put(key, value);
        }
    }

    /**
     * 添加样式（相同样式将覆盖）
     * StyleAttr.SUPPORT_STYLE_KEYS 支持的样式才能添加成功
     * @param styleMap 样式键值对
     */
    public void addStyle(Map<String,String> styleMap){
        if(styleMap != null && !styleMap.isEmpty()){
            for (Map.Entry<String,String> entry : styleMap.entrySet()) {
                String key = entry.getKey();
                addStyle(key, entry.getValue());
            }
        }
    }

    /**
     * 在解析 hmtl 样式之前，可以在此方法中设置默认样式
     * html 解析时， html 中的同名样式将覆盖默认样式
     */
    protected void initDefaultStyle(){

    }


    /**
     * 解析 html 标签，构建 pdf Element
     * @return 返回解析后的 PDF Element 对象
     */
    public abstract Element build();


    /**
     * 在 build 之后执行一些操作
     * @param el 当前 builder 创建的 Element 对象
     */
    public void afterBuild(Element el){

    }

}
